SimAntics
SimAntics is a CISC bytecode language which powers the objects in The Sims and The Sims Online. Development of SimAntics was coordinated by Jamie Doornbos with the help of Patrick J. Barrett III and Don Hopkins. Edith Objects for the game were programmed in an assembly intermediary of SimAntics using a developer tool called Edith, which is named after the first character produced for the game, Edith Bunker, and also stands for Edit Hierarchies or Edit House. The tool employs a box-and-arrow tree layout, in which each box describes an instruction and then points to one or more other boxes to direct control flow. This layout was designed and executed by Jamie Doornbos. The workspace was saved as metadata with the objects and was normally stripped before release; the NPCs, however, did not have their workspaces stripped, and they can be read along with their comments by the 3rd-party clone of Edith called Codex. Along with providing a tool editing interface, Edith allowed the programmer to load the Edith window alongside the game to immediately test newly created objects; thus, the E key was the "Edit House" command. Edith was not officially released outside of Maxis but was demonstrated in short videos by Don Hopkins, which can be found on the Movies section of his website, specifically, in this order: # The Sims Pie Menus (Edith demonstration) (47.1MB / 49,471,706 bytes) # Free The Sims Demo (7.94MB / 8,329,392 bytes) # Transmogrifier Demo (5.23MB / 5,493,860 bytes) # Object Exporter Demo (0.97MB / 1,026,770 bytes) # Person Exporter Demo (1.50MB / 1,578,455 bytes) : These videos were batch-uploaded by Don Hopkins on Sun, 01 Feb 2004 09:04:21 GMT according to the Last-Modified header of the files, although it seems they were recorded in 2000. EA also allowed a computer science class taught by Kenneth D. Forbus at Northwestern University in May 2001 and May 2002 to use Edith as part of their curriculum, but no students ever saved the software. Some documents were provided to the public describing the virtual machine: * Under the hood of The Sims * Programming Objects in The Sims (1.31MB / 1,383,488 bytes) The text strings used in the GUI for Edith are shipped with the game in both The Sims 1 and The Sims Online in a file named behavior.iff. Numerical constants as well can be found in the OTF files in the globals folder as well as the C++ headers located in the UIGraphics folder of both games. Leak Edith has been known since early 2012 to have been leaked in the final version of EA-Land. On December 22, 2012, a patch was released by Fatbag which launches Edith instead of the game. The patch can be downloaded here (please keep a copy of the entire original, unmodified game in a separate folder): * Edith.bps * Patch tool Note that certain features, such as spawning new instances of objects on a lot and debugging them, are inactive without a working game lot. In the Pre-Alpha version of The Sims Online (which was leaked on February 18, 2014), Edith can be launched through the use of the "edith" cheat. The cheat prompt can opened through Ctrl+Shift+C (like in The Sims 1) once you are logged in. Unlike The Sims 1, you must first authorize yourself to use cheats by entering the password "FullOpt" (case-insensitive) as a cheat into the cheat prompt. The protocol changes necessary to log in and enter Select-A-Sim in Pre-Alpha were determined on March 20th, 2014 and published in the Maxis Protocol article. The game can be forced into lot mode by starting with the command line option "-NoNetwork", however the simulation will be frozen. The complete list of arguments (as determined by the argument comparisons performed at TSOClient_base+0x9f6b in Pre-Alpha) is: nosound UseDBHostLayer lUKEnglish lFrench lGerman lItalian lSpanish lDutch lDanish lSwedish lNorwegian lFinnish lHebrew lRussian lPortuguese lJapanese lPolish lSimplifiedChinese lTraditionalChinese lThai lKorean lUSEnglish f r1024x768 3dhardware skip_memcheck skip_verify testmusic tuning_obj_depreciation skip_intro software_intro no_thread_init record replay nonetwork debug_objects rebuild_catalog non_us_locale show_init_progress soundguys no_autosave TestWindow factory NoNetwork works in every version of the game in our possession until the New & Improved US boxed version. Model SimAntics assembly is assembled into bytecode which is executed within a virtual thread granted to that object. Altogether, the virtual threads are executed synchronously (one after the other) in a nonpreemptive virtual machine, the SimAntics environment. Each object eventually relinquishes its control to the next object by calling the idle primitive or returning error; a return value of error tells the machine to kill the object and remove it from the lot, and if the game process was launched with the -debug_objects argument, the game will prompt a message that the object has crashed and provide its stack dump. Terminology * action * advertisement * attenuation * autonomy * behavior * bitfield * check * entry point * function * global * local * menu * node * object definition * parameter * primitive * private * scenario * semiglobal * slot * stack object * tree * tuning constant * variable Initialisms * SAS, CAS: Select-A-Sim, Create-A-Sim * GZ: Gonzo, a Maxis game development framework * RZ: Rizzo, built on top of Gonzo * EASTL: EA's Standard Template Library replacement, now released under the GPL: https://github.com/paulhodge/EASTL * LMS: Language Markup System * EOD: What it stands for is unknown, but it refers to custom menus that override the panel at the bottom of the screen when your Sim is dancing or playing black jack, for example. * AWC Text language Edith provides a menu option (File -> Save all behaviors...) that disassembles all of the behaviors in the game into txt files, categorized by their containing IFF files. Before looking at the binary structure of behaviors, it helps to first look at this text representation. The first line of the disassembly is the name of the IFF file, sans the file extension. For example, in behaviorscuckooclock.txt, cuckooclock Following this line is the disassembly for each behavior in the IFF file, sorted by ascending chunk ID. The first behavior in cuckooclock.iff is named "main": (main).000 Stack Object ID 0 assign ( := ) My object id true:1 (main).001 Global: Idle (with ticks=10) true:2 (main).002 Private: process true:1 As in C and C++, the main function is where execution for the object begins. When our particular object is added to the lot and run for the first time in Live mode, the object's ID will be written into the "Stack Object ID 0" variable. Upon true, it will branch to the instruction at index 1—in our case, simply the next one down. As the branch destination for false has not been specified, it is implicitly defined to error; that is, if the result of the instruction were false, the program would "branch" to error, deleting itself and informing the virtual machine that it has "crashed". Note that an object can delete itself off the lot at any time, without informing the virtual machine of a crash, by simply branching to true or false in the main function. The cuckooclock does not ever delete itself, however, so the only way to remove it is by selecting it with the hand tool and deleting it, which can be seen as "force closing" the process. The second instruction performs the "idle for X ticks" global with X=10; this relinquishes the object's execution context and returns true after 10 ticks have passed; in response, the program will branch to the instruction at index 2. The third instruction calls a private subroutine named "process" defined in the very same IFF file and then branches back to the previous instruction. In this short loop, we can see that this subroutine, "process", must return true to hand the context back to the virtual machine. Disassembly SimAntics makes use of little-endian integers. We will now analyze the executable format used for behaviors residing in BHAV chunks of the IFF files of the game. Header * Magic number - A 2-byte integer equal to 0x8000, 0x8001, 0x8002, or 0x8003 * Count - The total number of instructions defined in this behavior * Type - Usually 0, but may be 1, 2, 3, or 22 * Args - The number of arguments this subroutine expects to be passed. Up to four constant arguments can be passed in the call instruction; variable arguments or more than four arguments are passed through the use of temps. * Locals - The number of static variables allocated exclusively for this subroutine, which live for the life of the object * Flags - Attributes set for this subroutine Instruction * Opcode - A numerical value which identifies the meaning of this instruction * T-Dest - Zero-based index of the instruction in this behavior to jump to if the result of this instruction is true * F-Dest - Zero-based index of the instruction in this behavior to jump to if the result of this instruction is false : A destination of 255 (true), 254 (false), or 253 (error) may be supplied to return from a subroutine; a return value of 253 will kill the object that called the subroutine. * Operand data - Data passed alongside the opcode; format is dependent on the opcode Primitives In SimAntics, the opcode of an instruction can either refer to a built-in command, known as a primitive, or to a subroutine. The subroutines can be privates (belong to the object) semiglobals or globals. A private will have an opcode >= 4096 and a private will have an opcode >= 256. Instructions are executed synchronously within the thread until something yields the thread, an error is fired or the stack becomes empty. An example of this is the Animate Sim primitive. In the behaviours found in the game, this primitive often has a loopback on the false branch which points back to itself. The primitive returns true if the animation is complete and false if it is not. The false then loops back to the Animate Sim primitive to run the next frame. If this code was executed synchronously no animations would ever be observed. Therefore some primitives yield the thread. You can think of primitives as having the following return values. GOTO_TRUE, GOTO_FALSE, ERROR, GOTO_TRUE_YIELD, GOTO_FALSE_YIELD. The documentation below for primitives and their operands is correct for The Sims Online. The Sims 1 operands may be slightly different. 0 - Sleep Changes the current virtual thread's state to sleeping. Operand 4 and 5 (5 and 6 if counting from 1) contains the number of ticks to sleep for. 1 - Generic Sims Online Call 2 - Expression Performs a logical or mathematical expression. The operator value describes what type of expression to perform and the other values determine the left and right hand side of the expression. Operand: The lhsdata, lhsowner, rhsdata and rhsowner are scopes as described here. Possible values for operator: 3 - Report Metric 4 - grab 5 - drop 6 - Change Suit/Accessory 7 - Refresh 8 - Random Number 9 - burn 10 - Sims1.0 tutorial This primitive isn't used in any of the behaviors found in The Sims Online. 11 - Get Distance To 12 - Get Direction To 13 - Push Interaction 14 - Find Best Object for Function 15 - Break Point 16 - Find Location For 17 - idle for input Changes the current virtual thread's state to idle. Operand 4 and 5 (5 and 6 if counting from 1) contains the number of ticks to idle for, and if operand 6 and 7 (7 and 8 if counting from 1) are non-zero, this state is interruptable (meaning that a new function can be invoked on the stack at any time). 18 - Remove Object Instance 19 - make new character 20 - Run Functional Tree 21 - show string 22 - look towards 23 - Play Sound Event 24 - old relationship 25 - Transfer Funds 26 - Relationship 27 - Go To Relative Position 28 - Run Tree by Name 29 - Set Motive Change 30 - Syslog 31 - Set to Next 32 - Test Object Type 33 - find 5 worst motives 34 - ui effect 35 - Special Effect 36 - Dialog - Private Strings 37 - Test Sim Interacting With 38 - Dialog - Global Strings 39 - Dialog - Semi-Global Strings 40 - OnlineJobsCall 41 - Set Balloon/Headline 42 - Create New Object Instance 43 - drop onto 44 - Animate Sim 45 - Go To Routing Slot 46 - Snap 47 - reach 48 - Stop ALL Sounds 49 - Notify the Stack Object out of Idle 50 - Add/Change the Action String 51 - prim 51 - (used in Sims 2.0) This primitive isn't used in any of the behaviors found in The Sims Online. 52 - prim 52 - (used in Sims 2.0) This primitive isn't used in any of the behaviors found in The Sims Online. 53 - prim 53 - (used in Sims 2.0) This primitive isn't used in any of the behaviors found in The Sims Online. 54 - prim 54 - (used in Sims 2.0) This primitive isn't used in any of the behaviors found in The Sims Online. 55 - Sync Field 56 - Ownership 57 - Start Persistant Dialog 58 - End Persistant Dialog 59 - Update Persistant Dialog 60 - Poll Persistant Dialog 61 - Send Maxis Letter 62 - Invoke Plugin 63 - Get Terrain Info 64 - Leave Lot and Goto 65 - Find Best Action 66 - Set Dynamic Object Name 67 - Inventory Operations Scopes Several primitives make reference to variables stored in the VM to perform their actions. For example, the random number primitive provides the location of a variable for the random range. Usually (but not always) these take the form of two fields, a variable owner and variable data. The owner can be thought of like a scope and the possible values for this are described below. 0 - my objects attributes Objects use attributes to store persistent information, e.g. whether the fish in the fish tank are dead or alive. This scope gets/sets an attribute for the object occupying the "My" pointer in the stack frame. The data value is the attribute index. It seems (based on a handful of files) like a string table with ID = 256 in the objiff file contains labels for the attributes. 1 - stack objects attributes Same as "my objects attributes" except against the object occupying the stack object pointer in the stack frame. 2 - targ obj attr (DO NOT USE) Judging from the capital letters, this probably isn't used anywhere ingame. 3 - my object This refers to an objects built in fields such as which graphic is displaying or how dirty the object is. Below are the possible values for the data field. 4 - stack object Same as my object but against the object occupying the stack object in the stack frame. 5 - targ obj's (DO NOT USE) Same as 2. Probably a leftover of an older more limited "stack object" system SimAntics used to use. 6 - Global ( from avatar ) Most likely accesses the global with the index specified. (from avatar) probably serves as a reminder that values can be different per player. 7 - literal Numeric literal. Use the value in the data field. 8 - temps Temporary registers. The data field is used as the index. The current assumption is that these are contextual to the thread but may be VM wide or related to stack objects. 9 - parameters This refers to the arguments passed into a sub-routine call when the stack was pushed. The data field represents the parameter index. 10 - stack object id This scope behaves more like a global. It allows you to reference or change the object occupying the stack object in the stack frame. For example, objects quite often in their init routine assign this to the My.objectId property. 11 - Temptemp Accessing a temporary register with another temp as a pointer...? I've yet to see this used. 12 - check tree ad range I wish I knew what this meant. Probably to do with the object's motive advertisements (might drive free will?). 13 - stack obj's temp Accesses temp register of stack obj. See 8. 14 - my motives Accesses motives. Still need to look into the number --> name relation. 15 - stack obj's motives Same as above but for the stack object. 16 - stack object's slot See 20. 17 - stack obj's motivetemp Accesses motives in a different way from 14, presumably using a temp variable (id as data passed) to select the motive. 18 - my person data A similar idea to the built in fields, but there are 100 fields and they don't seem to be available on objects that are not people. Table of names coming shortly... (really we need a whole wiki for all of this) 19 - stack obj's person data Same as above, but accesses the person data of the stack object instead. 20 - my slot Slots are most likely positions that objects can be placed on top of, eg. a plate is placed in a slot owned by a counter, a sitting sim is placed in a slot owned by the chair, a stacked plate is placed in a slot owned by the plate below it... Used in chairs' "sit function" methods to presumably determine if the sim is already sitting in the seat (if they are then do nothing). 21 - stack objects definition Refers to OBJD attributes for the stack object. The data value refers to the field ID. It is not yet clear if these indexes change depending on the OBJD version. If so index information will need to be persisted. 22 - stack object's attrparam Info pending 23 - room0 Info pending 24 - neighbor in stack object Info pending 25 - local Local variables for the BHAV. When the stack is pushed the BHAV may alloc space for locals. The data field is the local index. 26 - stack object tuning Tuning constants for the stack object. The most significant 9 bits of the data field are used to calculate the table ID as such: 4096 + (data >> 7). The first 7 bits of the data field are the tuning variable index. The values can be stored in either BCON or OTF tables. 27 - Dyn. Sprite Flagtemp of Stack Object Checks if one of the stack object's Dynamic Sprite Flags are set. Returns 1 for true and 0 for false. 28 - check tree ad personality var Similar to 12, but with the personality advertisements instead (eg. used in behavior where neat sims are more likely to use the sink). Unsure of format, function or returned value for now. 29 - check tree ad min Info pending 30 - my person data temp Accesses the person data referenced by a temp register. 31 - stack obj's person data temp Same as above but with the stack object. 32 - neighbor's person data Accesses the person data of "neighbor". Not sure what this means at the moment. 33 - job data 0, 1 Info pending, probably not used in TSO in favor of OnlineJobs system 34 - neighborhood data Codex doesn't even have control over this scope implemented, so definitely not sure. 35 - stack object's function Probably returns the BHAV id of the function currently running in the stack object. 36 - my type attr Info pending 37 - stack obj's type attr Info pending